/*
 *  Copyright 2004 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.webapp.taglib.core.html;

import com.blandware.atleap.common.util.StringUtil;
import com.blandware.atleap.webapp.util.core.ApplicationResources;
import com.blandware.atleap.webapp.util.core.WebappUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.taglib.TagUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.util.Locale;

/**
 * <p>Provides ability to get message from bundle and show it on page or save it in some scope.
 * If <b>language</b> is not specified, user language is obtained. If no message
 * for this language was found, then default language is tried. If still not
 * found, any language that contains a message for given key will be used.
 * </p>
 * <p>
 * Allowed attributes are:
 * <ul>
 * <li>
 * <b>key</b> - bundle key for which to obtain message
 * </li>
 * <li>
 * <b>language</b> - language for which to obtain message. This must be a
 * lowercase two-letter ISO-639 code (for example, "en").
 * If not given, user language is obtained. If no message was found for this
 * language, then first default
 * language is tried and, if message was not still found, any language may supply
 * a message.
 * </li>
 * <li>
 * <b>ignore</b> - whether to ignore a situation when no message was found for
 * any language. If "true" and no message was found, no exception will be thrown,
 * message will just be treated as empty one. Default is "false".
 * </li>
 * <li>
 * <b>filter</b> - whether to encode HTML-sensitive characters (like ampersand)
 * when writing result to page. Default is "false".
 * </li>
 * <li>
 * <b>var</b> - name of scope variable that will accept obtained message. If
 * not specified, message will be written to page.
 * </li>
 * <li>
 * <b>scope</b> - scope of variable to export message to
 * </li>
 * <li>
 * <b>arg<em>N</em></b> - value of argument number <em>N</em> to put to message
 * instead of placeholder (<em>N</em> is an integer between 0 and 4).
 * </li>
 * </ul>
 * </p>
 * <p><a href="MessageTag.java.html"><i>View Source</i></a></p>
 *
 * @author Sergey Zubtsovskiy <a href="mailto:sergey.zubtsovskiy@blandware.com">&lt;sergey.zubtsovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.5 $ $Date: 2006/08/03 10:08:23 $
 * @jsp.tag name="message"
 * body-content="empty"
 */
public class MessageTag extends SimpleTagSupport {

	protected transient final Log log = LogFactory.getLog(MessageTag.class);

	/**
	 * Key in bundle to get message for
	 */
	protected String key;

	/**
	 * Whether or not to throw an exception if message for specified key could not be found
	 */
	protected Boolean ignore = Boolean.FALSE;

	/**
	 * Whether or not to replace all HTML-sensitive characters with their entity equivalents
	 */
	protected Boolean filter = Boolean.FALSE;

	/**
	 * Name of variable to export message to
	 */
	protected String var;

	/**
	 * Scope to export message to
	 */
	protected String scope;

	/**
	 * Language to get value for. By default Struts locale is used
	 */
	protected String language;

	/**
	 * The first optional argument.
	 */
	protected String arg0 = null;

	/**
	 * The second optional argument.
	 */
	protected String arg1 = null;

	/**
	 * The third optional argument.
	 */
	protected String arg2 = null;

	/**
	 * The fourth optional argument.
	 */
	protected String arg3 = null;

	/**
	 * The fifth optional argument.
	 */
	protected String arg4 = null;


	/**
     * Returns bundle key for this message
     *
	 * @return bundle key
	 * @jsp.attribute required="true"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Key in bundle to get message for"
	 */
	public String getKey() {
		return key;
	}

    /**
     * Sets bundle key for this message
     *
     * @param key bundle key to set
     */
	public void setKey(String key) {
		this.key = key;
	}

	/**
     * Return whether to ignore errors if they occure while getting message
     *
	 * @return whether to ignore exception if it occure while getting message
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.Boolean"
	 * description="Whether or not to throw an exception if message for specified key could not be found"
	 */
	public Boolean getIgnore() {
		return ignore;
	}

    /**
     * Sets whether to ignore errors if they occure while getting message
     *
     * @param ignore whether to ignore exception if it occure while getting message
     */
	public void setIgnore(Boolean ignore) {
		this.ignore = ignore;
	}

	/**
     * Returns whether or not to replace all HTML-sensitive characters with their entity equivalents
     *
	 * @return whether or not to replace all HTML-sensitive characters
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.Boolean"
	 * description="Whether or not to replace all HTML-sensitive characters
	 */
	public Boolean getFilter() {
		return filter;
	}

    /**
     * Sets whether or not to replace all HTML-sensitive characters with their entity equivalents
     *
     * @param filter whether or not to replace all HTML-sensitive characters
     */
	public void setFilter(Boolean filter) {
		this.filter = filter;
	}

	/**
     * Returns language code for which the value will be obtained
     *
	 * @return language code
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Locale to get value for"
	 */
	public String getLanguage() {
		return language;
	}

    /**
     * Sets language code for which the value will be obtained
     *
     * @param language language code to set
     */
	public void setLanguage(String language) {
		this.language = language;
	}

	/**
     * Returns name of variable that will accept the obtained value
     *
     * @return name of variable
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Name of variable to export message"
	 */
	public String getVar() {
		return var;
	}

    /**
     * Sets name of variable that will accept the obtained value
     *
     * @param var name of variable to set
     */
	public void setVar(String var) {
		this.var = var;
	}

	/**
     * Returns variable scope
     *
     * @return variable scope
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="Scope to export variable to"
	 */
	public String getScope() {
		return scope;
	}

    /**
     * Sets variable scope
     *
     * @param scope variable scope to set
     */
	public void setScope(String scope) {
		this.scope = scope;
	}

	/**
     * Returns first argument
     *
	 * @return first argument
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The first optional argument."
	 */
	public String getArg0() {
		return arg0;
	}

    /**
     * Sets first argument
     *
     * @param arg0 first argument to set
     */
	public void setArg0(String arg0) {
		this.arg0 = arg0;
	}

	/**
     * Returns second argument
     *
	 * @return second argument
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The second optional argument."
	 */
	public String getArg1() {
		return arg1;
	}

    /**
     * Sets second argument
     *
     * @param arg1 second argument to set
     */
	public void setArg1(String arg1) {
		this.arg1 = arg1;
	}


	/**
     * Returns third argument
     *
	 * @return third argument
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The third optional argument."
	 */
	public String getArg2() {
		return arg2;
	}

    /**
     * Sets third argument
     *
     * @param arg2 third argument to set
     */
	public void setArg2(String arg2) {
		this.arg2 = arg2;
	}

	/**
     * Returns fourth argument
     *
	 * @return fourth argument
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The fourth optional argument."
	 */
	public String getArg3() {
		return arg3;
	}

    /**
     * Sets fourth argument
     *
     * @param arg3 fourth argument to set
     */
	public void setArg3(String arg3) {
		this.arg3 = arg3;
	}


	/**
     * Returns fifth argument
     *
	 * @return fifth argument
	 * @jsp.attribute required="false"
	 * rtexprvalue="true"
	 * type="java.lang.String"
	 * description="The fifth optional argument."
	 */
	public String getArg4() {
		return arg4;
	}

    /**
     * Sets fifth argument
     *
     * @param arg4 fifth argument to set
     */
	public void setArg4(String arg4) {
		this.arg4 = arg4;
	}

    /**
     * Processes the tag
     *
     * @throws JspException
     */
	public void doTag() throws JspException {

		PageContext pageContext = (PageContext) getJspContext();
		HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();

		if ( ignore == null ) {
			ignore = Boolean.FALSE;
		}

		if ( filter == null ) {
			filter = Boolean.FALSE;
		}

		Locale locale = null;
		if ( language != null ) {
			locale = new Locale(language);
		} else {
			locale = WebappUtil.getEnsuredUserLocale(request);
			if ( locale == null ) {
				locale = Locale.getDefault();
			}
		}

		Object[] args = null;
		if ( arg0 != null || arg1 != null || arg2 != null || arg3 != null || arg4 != null ) {
			args = new Object[]{arg0, arg1, arg2, arg3, arg4};
		}
		
		String message = ApplicationResources.getInstance(pageContext.getServletContext()).getMessage(locale, key, args);

		if ( message == null ) {
			if ( !ignore.booleanValue() ) {
				JspException e = new JspException("No message for key '" + key + "' could be found");
				throw e;
			} else {
				if ( log.isDebugEnabled() ) {
					log.debug("No message for key '" + key + "' could be found. Ignored");
				}
			}
		} else if ( message.length() == 0 ) {
			if ( log.isDebugEnabled() ) {
				log.debug("Value for key '" + key + "' is empty string");
			}
		}

		TagUtils tagUtils = TagUtils.getInstance();
		if ( var != null ) {
			// save message in specified scope
			int varScope = PageContext.PAGE_SCOPE;
			if ( scope != null ) {
				varScope = tagUtils.getScope(scope);
			}
			pageContext.setAttribute(var, message, varScope);

		} else {

			// encode HTML-sensitive characters if requested
			if ( filter.booleanValue() ) {
				message = StringUtil.htmlEncode(message);
			}

			// write message directly to page
			tagUtils.write(pageContext, message);
		}

	}
}
